package io.sodabox.common.utils;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

import com.google.common.base.Function;


public class Pair<A, B> {

	private final A first;
	private final B second;

	/**
	 * Creates a new pair.
	 *
	 * @param first The first value.
	 * @param second The second value.
	 */
	public Pair( A first,  B second) {
		this.first = first;
		this.second = second;
	}


	public A getFirst() {
		return first;
	}


	public B getSecond() {
		return second;
	}

	@Override
	public boolean equals(Object o) {
		if (o == this) { return true; }
		if (!(o instanceof Pair)) { return false; }

		@SuppressWarnings("rawtypes")
		Pair that = (Pair) o;
		return new EqualsBuilder()
		.append(this.first, that.first)
		.append(this.second, that.second)
		.isEquals();
	}

	@Override
	public String toString() {
		return String.format("(%s, %s)", getFirst(), getSecond());
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder()
		.append(first)
		.append(second)
		.toHashCode();
	}

	/**
	 * Creates a function that can extract the first item of pairs of the given type parametrization.
	 *
	 * @param <S> The type of the 1st item in the pair.
	 * @param <T> The type of the 2nd item in the pair.
	 * @return A function that will extract the 1st item in a pair.
	 */
	public static <S, T> Function<Pair<S, T>, S> first() {
		return new Function<Pair<S, T>, S>() {
			public S apply(Pair<S, T> pair) {
				return pair.first;
			}
		};
	}

	/**
	 * Creates a function that can extract the second item of pairs of the given type parametrization.
	 *
	 * @param <S> The type of the 1st item in the pair.
	 * @param <T> The type of the 2nd item in the pair.
	 * @return A function that will extract the 2nd item in a pair.
	 */
	public static <S, T> Function<Pair<S, T>, T> second() {
		return new Function<Pair<S, T>, T>() {
			public T apply(Pair<S, T> pair) {
				return pair.second;
			}
		};
	}

	/**
	 * Convenience method to create a pair.
	 *
	 * @param a The first value.
	 * @param b The second value.
	 * @param <A> The type of the 1st item in the pair.
	 * @param <B> The type of the 2nd item in the pair.
	 * @return A new pair of [a, b].
	 */
	public static <A, B> Pair<A, B> of( A a,  B b) {
		return new Pair<A, B>(a, b);
	}
}